/*
 * Copyright 2023, Haiku, Inc. All rights reserved.
 * Distributed under the terms of the MIT License.
 */

#ifndef LS7A2000_ACCELERANT_H
#define LS7A2000_ACCELERANT_H

#include <Accelerant.h>
#include <Drivers.h>
#include <PCI.h>

#include "video_overlay.h"

#define ENABLE_DEBUG_TRACE 0

#ifdef ENABLE_DEBUG_TRACE
extern "C" void _sPrintf(const char *format, ...);
#define TRACE(x...) _sPrintf("ls7a2000: " x)
#else
#define TRACE(x...) ;
#endif

#define LS7A2000_PRIVATE_DATA_MAGIC 'ls7a'

// info about PLL, display timing, etc.
struct display_mode;

typedef struct
{
    uint32 magic;              // magic number for driver
    area_id shared_info_area;  // the area_id of the shared info
    display_mode current_mode; // current display mode
    display_mode panel_mode;   // flat panel native mode
    uint32 frame_buffer_offset;

    // cursor
    uint32 cursor_buffer_offset;
    uint32 cursor_format;
    uint16 cursor_hot_x;
    uint16 cursor_hot_y;

    // color spaces supported by current video chip/driver
    uint32 mode_count;
    area_id mode_list_area; // area containing display_mode list
    uint32 bytes_per_row;   // number of bytes in each row

    // memory mappings
    area_id regs_area;         // area of memory mapped registers
    area_id frame_buffer_area; // area of frame buffer

    // physical addresses
    phys_addr_t physical_graphics_memory;
    phys_addr_t physical_frame_buffer;
    phys_addr_t physical_registers;

    // virtual addresses
    vuint8 *graphics_memory; // virtual memory address
    vuint8 *frame_buffer;    // virtual frame buffer address
    vuint8 *cursor_memory;   // virtual cursor address
    vuint8 *regs;            // virtual registers address

    // semaphores
    sem_id vertical_blanking_sem;
} shared_info;

typedef struct
{
    void *frame_buffer;
    area_id area;
    uint32 bytes_per_row;
    uint32 bits_per_pixel;
    uint32 width;
    uint32 height;
} frame_buffer_config;

typedef struct
{
    bool is_clone;
    int device;
    shared_info *shared_info;
    area_id shared_info_area;
    display_mode *mode_list;
    area_id mode_list_area;
    uint32 current_mode;
} accelerant_info;

// register access
inline uint32
read32(uint32 offset)
{
    return *(volatile uint32 *)(gInfo->shared_info->regs + offset);
}

inline void
write32(uint32 offset, uint32 value)
{
    *(volatile uint32 *)(gInfo->shared_info->regs + offset) = value;
}

// globals
extern accelerant_info *gInfo;

// accelerant.cpp
status_t ls7a2000_init_accelerant(int device);
void ls7a2000_uninit_accelerant(void);
status_t ls7a2000_get_accelerant_device_info(accelerant_device_info *info);
status_t ls7a2000_get_frame_buffer_config(frame_buffer_config *config);
status_t ls7a2000_accelerant_clone_info_size(void);
status_t ls7a2000_get_accelerant_clone_info(void *info);
status_t ls7a2000_clone_accelerant(void *info);
sem_id ls7a2000_accelerant_retrace_semaphore(void);

// mode.cpp
uint32 ls7a2000_accelerant_mode_count(void);
status_t ls7a2000_get_mode_list(display_mode *mode_list);
status_t ls7a2000_set_display_mode(display_mode *mode);
status_t ls7a2000_get_display_mode(display_mode *currentMode);
status_t ls7a2000_get_edid_info(void *info, size_t size, uint32 *_version);
status_t ls7a2000_get_pixel_clock_limits(display_mode *mode, uint32 *low, uint32 *high);
status_t create_mode_list(void);

// cursor.cpp
status_t ls7a2000_set_cursor_shape(uint16 width, uint16 height, uint16 hotX, uint16 hotY, uint8 *andMask, uint8 *xorMask);
void ls7a2000_move_cursor(uint16 x, uint16 y);
void ls7a2000_show_cursor(bool is_visible);

#endif // LS7A2000_ACCELERANT_H